package com.example.voucher.config;

import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Properties;
import java.util.function.Function;
import java.util.stream.Collectors;

import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import com.example.voucher.config.bo.MappingItemBO;
import com.example.voucher.config.bo.ReducingConfigBO;
import com.example.voucher.config.bo.ScenarioReducingConfigBO;
import com.example.voucher.config.bo.SubjectMappingConfigBO;
import com.example.voucher.config.bo.SubjectReducingConfigBO;
import com.example.voucher.config.bo.TenantReducingConfigBO;
import com.google.common.collect.HashBasedTable;
import com.google.common.collect.Lists;
import com.google.common.collect.Table;

@Component
public class SubjectConfigRegister {

    @Autowired
    private TenantMirrorConfig mirrorConfig;

    private static final Logger LOGGER = LoggerFactory.getLogger(SubjectConfigRegister.class);

    // R为tenantCode C为凭证场景 V为科目相关配置
    private Table<String, String, List<String>> subjectListTable = HashBasedTable.create();
    private Table<String, String, List<SubjectReducingConfigBO>> reducingTable = HashBasedTable.create();
    private Table<String, String, List<SubjectMappingConfigBO>> mappingTable = HashBasedTable.create();

    public List<String> getSubjectConfig(String tenantCode, String scenarioCode) {
        List<String> list = subjectListTable.get(tenantCode, scenarioCode);
        if (CollectionUtils.isEmpty(list)) {
            String mirrorTenantCode = mirrorConfig.getMirror(tenantCode);
            if (StringUtils.isNotBlank(mirrorTenantCode)) {
                List<String> mirrorSubjectList = subjectListTable.get(mirrorTenantCode, scenarioCode);
                if (CollectionUtils.isNotEmpty(mirrorSubjectList)) {
                    LOGGER.warn("找不到租户=【{}】场景=【{}】需要生成哪些科目相关的配置，模拟租户【{}】", tenantCode, scenarioCode, mirrorTenantCode);
                    list = mirrorSubjectList;
                }
            }
        }
        if (CollectionUtils.isEmpty(list)) {
            throw new RuntimeException(String.format("找不到租户=【{%s}】场景=【{%s}】需要生成哪些科目相关的配置", tenantCode, scenarioCode));
        }
        return list;
    }

    public Map<String, SubjectReducingConfigBO> getReducingConfig(String tenantCode, String scenarioCode) {
        List<SubjectReducingConfigBO> list = reducingTable.get(tenantCode, scenarioCode);

        if (CollectionUtils.isEmpty(list)) {
            String mirrorTenantCode = mirrorConfig.getMirror(tenantCode);
            if (StringUtils.isNotBlank(mirrorTenantCode)) {
                List<SubjectReducingConfigBO> mirrorList = reducingTable.get(mirrorTenantCode, scenarioCode);
                if (CollectionUtils.isNotEmpty(mirrorList)) {
                    LOGGER.warn("找不到租户=【{}】场景=【{}】科目分组汇总相关的配置，模拟租户【{}】", tenantCode, scenarioCode, mirrorTenantCode);
                    list = mirrorList;
                }
            }
        }
        if (CollectionUtils.isEmpty(list)) {
            throw new RuntimeException(String.format("找不到租户=【{%s}】场景=【{%s}】科目分组汇总相关的配置", tenantCode, scenarioCode));
        }
        
        return list.stream()
            .collect(Collectors.toMap(SubjectReducingConfigBO::getSubject, Function.identity(), (t1, t2) -> t1));
    }

    public Map<String, SubjectMappingConfigBO> getMappingConfig(String tenantCode, String scenarioCode) {
        List<SubjectMappingConfigBO> list = mappingTable.get(tenantCode, scenarioCode);

        if (CollectionUtils.isEmpty(list)) {
            String mirrorTenantCode = mirrorConfig.getMirror(tenantCode);
            if (StringUtils.isNotBlank(mirrorTenantCode)) {
                List<SubjectMappingConfigBO> mirrorList = mappingTable.get(mirrorTenantCode, scenarioCode);
                if (CollectionUtils.isNotEmpty(mirrorList)) {
                    LOGGER.warn("找不到租户=【{}】场景=【{}】科目字段映射相关的配置，模拟租户【{}】", tenantCode, scenarioCode, mirrorTenantCode);
                    list = mirrorList;
                }
            }
        }
        if (CollectionUtils.isEmpty(list)) {
            throw new RuntimeException(String.format("找不到租户=【{%s}】场景=【{%s}】科目字段映射相关的配置", tenantCode, scenarioCode));
        }
        
        return list.stream()
            .collect(Collectors.toMap(SubjectMappingConfigBO::getSubject, Function.identity(), (t1, t2) -> t1));
    }

    private void registerReducingConfig(String tenantCode, String scenarioCode, List<SubjectReducingConfigBO> list) {
        List<SubjectReducingConfigBO> existedCofing = reducingTable.get(tenantCode, scenarioCode);
        if (existedCofing != null && existedCofing.size() > 0) {
            LOGGER.error("重复注册分组汇总相关的配置");
            return;
        }
        reducingTable.put(tenantCode, scenarioCode, list);
    }

    public void registerReducingConfig(ReducingConfigBO bo) {
        Map<String, TenantReducingConfigBO> reducingConfigMap = bo.getReducingConfig();
        for (Map.Entry<String, TenantReducingConfigBO> entry : reducingConfigMap.entrySet()) {
            String tenantCode = entry.getKey();
            TenantReducingConfigBO tenantReducingConfig = entry.getValue();
            List<ScenarioReducingConfigBO> scenarioList = tenantReducingConfig.getScenarioList();
            if (CollectionUtils.isNotEmpty(scenarioList)) {
                for (ScenarioReducingConfigBO scenarioReducingConfig : scenarioList) {
                    registerReducingConfig(tenantCode, scenarioReducingConfig.getScenario(),
                        scenarioReducingConfig.getSubjectList());
                }
            }
        }
    }

    public void registerMappingConfig(String tenantCode, String scenarioCode, SubjectMappingConfigBO config) {
        List<String> subjectList = subjectListTable.get(tenantCode, scenarioCode);
        List<SubjectMappingConfigBO> existedCofing = mappingTable.get(tenantCode, scenarioCode);
        if (subjectList == null) {
            subjectList = Lists.newArrayList();
            subjectListTable.put(tenantCode, scenarioCode, subjectList);
            existedCofing = Lists.newArrayList();
            mappingTable.put(tenantCode, scenarioCode, existedCofing);
        }
        subjectList.add(config.getSubject());
        existedCofing.add(config);
    }

    public void registerMappingConfig(String tenantCode, String scenarioCode, String subject, Properties prop) {
        SubjectMappingConfigBO mappingConfigBO = new SubjectMappingConfigBO();
        mappingConfigBO.setSubject(subject);
        List<MappingItemBO> list = Lists.newArrayList();
        mappingConfigBO.setList(list);
        for (Entry<Object, Object> entry : prop.entrySet()) {
            String k = (String)entry.getKey(); // po(Voucher)的属性
            String v = (String)entry.getValue(); // ognl，数据源VoucherItemAccessor
            if (v != null && StringUtils.isNotBlank(v)) {
                list.add(new MappingItemBO(k, v));
            }
        }
        registerMappingConfig(tenantCode, scenarioCode, mappingConfigBO);
    }

}
